/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.expense.app.admin.aop;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.expense.app.admin.services.AdminUserServ;
import com.expense.common.constant.enums.ResultCode;
import com.expense.common.exception.PlatformException;
import com.expense.common.model.auth.AdminUser;
import com.expense.common.util.UserUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author lengleng
 * @date 2017/12/15
 * Controller 增强
 */

@Aspect
@Configuration
public class ControllerAop {
    private static final Log log = LogFactory.get();

    @Autowired
    AdminUserServ adminUserServ;

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *) && !@annotation(com.expense.app.admin.annotation.IgnoreAuth)")
    public void pointCutAuthContrller() {}

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void pointCutLog() {}

    /**
     * 拦截器具体实现
     *
     * @param pjp 切点 所有有权限访问的Controller
     * @return Result  结果包装
     */
    @Around("pointCutAuthContrller()")
    public Object AuthControllerHandler(ProceedingJoinPoint pjp) throws Throwable {
        Object result;
        log.info("进入Controller");
        // 获取登录用户AdminUser
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Long userId = UserUtils.getUserId(request);
        AdminUser adminUser =  adminUserServ.getAdminUser(userId);
        if(adminUser == null) throw new PlatformException(ResultCode.NO_LOGIN.getCode(),"登录信息失效，请重新登录!");
        UserUtils.setUser(adminUser);

        //TODO 判断用户是否有功能权限
        result = pjp.proceed();
        log.info("走出Controller");
        UserUtils.clearAllUserInfo();
        return result;
    }

    @Around("pointCutLog()")
    public Object LogHandler(final ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        log.info("日志: URL          : " + request.getRequestURL().toString());
        log.info("日志: HTTP_METHOD  : " + request.getMethod());
        log.info("日志: IP           : " + request.getRemoteAddr());
        log.info("日志: CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
        log.info("日志: ARGS         : " + ArrayUtil.join(pjp.getArgs(),"--"));

        Object result;

        result = pjp.proceed();
        log.info("日志: "+pjp.getSignature() + " 用时: " + (System.currentTimeMillis() - startTime)+" ms");

        return result;
    }
}
